﻿using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;

namespace DimensionsHelper.LanguageService.Syntax;

public class ArrayDeclaration : VariableDeclaration
{
    private readonly int _rank;
    private IntegerLiteral?[] _boundaries;

    internal ArrayDeclaration(Identifier name, SyntaxNode? parent) :
        base(SyntaxKinds.ArrayDeclaration, name, parent)
    {
        _boundaries = [];
    }


    /// <summary>
    ///     数组维度数
    /// </summary>
    public int Rank
    {
        get => _rank;

        internal init
        {
            if ((_boundaries.Length > 0 && _boundaries.Length == _rank) || value <= 0)
            {
                return;
            }

            Array.Resize(ref _boundaries, _rank);
            _rank = value;
        }
    }


    /// <summary>
    ///     已定义的维度数
    /// </summary>
    public int BoundariesCount => _boundaries.Length;


    /// <summary>
    ///     获取指定维度的边界定义，如果维度数无效或未定义，返回null。
    /// </summary>
    public IntegerLiteral? GetBoundary(int rank)
    {
        if (rank < 1 || rank > _boundaries.Length)
        {
            return null;
        }

        return _boundaries[rank - 1];
    }


    /// <summary>
    ///     尝试获取指定维度的边界定义，如果维度数无效或者未定义，返回false。
    /// </summary>
    /// <param name="rank"></param>
    /// <param name="boundary"></param>
    /// <returns></returns>
    public bool TryGetBoundary(int rank, [MaybeNullWhen(false)] out IntegerLiteral boundary)
    {
        boundary = null;

        if (rank <= 0 || rank > _boundaries.Length)
        {
            return false;
        }

        boundary = _boundaries[rank - 1];
        return boundary != null;
    }


    /// <summary>
    ///     设置指定维度的数组长度边界。
    /// </summary>
    /// <param name="rank">指定维度，1开始</param>
    /// <param name="boundary">边界定义，如果是null，则视为未定义</param>
    public void SetBoundary(int rank, IntegerLiteral? boundary)
    {
        Debug.Assert(rank >= 1);

        if (rank > _boundaries.Length)
        {
            Array.Resize(ref _boundaries, rank);
        }
        else
        {
            IntegerLiteral? oldBound = _boundaries[rank];

            if (oldBound != null)
            {
                oldBound.Parent = null;
            }
        }

        _boundaries[rank - 1] = boundary;

        if (boundary != null)
        {
            boundary.Parent = this;
        }
    }


    public override void AcceptVisitor<T>(SyntaxNodeVisitor<T> visitor)
    {
        Accept(visitor, NameIdentifier);
        AcceptList(visitor, _boundaries);
    }
}


public static partial class NodeFactory
{
    public static ArrayDeclaration CreateArrayDeclaration(SyntaxNode? parent, Identifier identifierName)
    {
        return new ArrayDeclaration(identifierName, parent);
    }


    public static ArrayDeclaration CreateArrayDeclaration(SyntaxNode? parent, Identifier identifierName,
        IReadOnlyList<IntegerLiteral?> boundaries)
    {
        Debug.Assert(boundaries.Count > 0);

        ArrayDeclaration decl = new(identifierName, parent)
        {
            Rank = boundaries.Count
        };

        for (int i = 0; i < boundaries.Count; i++)
        {
            decl.SetBoundary(i + 1, boundaries[i]);
        }

        return decl;
    }
}